/*
 * ServiceMessage.java
 *
 * Created on 29 March 2012, 09:23
 *
 * To change this template, choose Tools | Template Manager
 * and open the template in the editor.
 */

package Simulation.Messages;

import Simulation.Utils.ByteArrayUtils;

/**
 *
 * @author aking2
 */
public class Message {
    
    public enum MessageIdEnum {
        
        // Messages indicating status of the messaging service itself
        
        MESSAGE_NONE,
        MESSAGE_BAD_DATA_DETECTED,
        MESSAGE_TIMEOUT,
        MESSAGE_NOT_INITIALISED,
        
        // Main synchronisation Messages
        
        SYNC_PROCESS_INPUTS,
        SYNC_SEND_OUTPUTS,
        SYNC_SEND_LAST_TO_CIGI,
        SYNC_SEND_LAST_TO_DIS,
        
        // IOS Messages. Note that these are automatically sent on different networks.
        
        IOS_HEALTH,
        IOS_DESIGNATE_HOST_CONFIG,
        IOS_PERFORMANCE_RESULT,
        IOS_START_SIMULATING,
        IOS_STOP_SIMULATING,
        IOS_REPOSITION,
        IOS_RECONSTITUTE,
        IOS_REORIENT,
        IOS_RESUPPLY,
        IOS_RESTART_SOFTWARE,
        
        
        // Messages From the Vehicle Behaviours
        
        BEHV_HOST_CONFIG,
        
        // DIS_WRAPPED
        
        DIS_INCOMING_WRAPPED,
        DIS_OUTGOING_WRAPPED
    };
    
    public static int EnumToInt( MessageIdEnum msg) {
        int result = 0;
        
        switch( msg ) {
            case MESSAGE_NONE:                  result =   0; break;
            case MESSAGE_BAD_DATA_DETECTED:     result =   1; break;
            case MESSAGE_TIMEOUT:               result =   2; break;
            case MESSAGE_NOT_INITIALISED:       result =   3; break;
                
            case SYNC_PROCESS_INPUTS:           result = 100; break;
            case SYNC_SEND_OUTPUTS:             result = 101; break;
            case SYNC_SEND_LAST_TO_CIGI:        result = 102; break;
            case SYNC_SEND_LAST_TO_DIS:         result = 103; break;
                
            case IOS_HEALTH:                    result = 200; break;
            case IOS_DESIGNATE_HOST_CONFIG:     result = 201; break;
            case IOS_PERFORMANCE_RESULT:        result = 202; break;
            case IOS_START_SIMULATING:          result = 203; break;
            case IOS_STOP_SIMULATING:           result = 204; break;
            case IOS_REPOSITION:                result = 205; break;
            case IOS_RECONSTITUTE:              result = 206; break;
            case IOS_REORIENT:                  result = 207; break;
            case IOS_RESUPPLY:                  result = 208; break;
            case IOS_RESTART_SOFTWARE:          result = 209; break;
                
            case BEHV_HOST_CONFIG:              result = 300; break;   
                
            case DIS_INCOMING_WRAPPED:          result = 800; break;
            case DIS_OUTGOING_WRAPPED:          result = 801; break;                
        }
        
        return result;
    }
    
    
    public static MessageIdEnum IntToEnum(int msg) {
        MessageIdEnum result;
        
        switch( msg ) {
            case   0:   result = MessageIdEnum.MESSAGE_NONE;                break;
            case   1:   result = MessageIdEnum.MESSAGE_BAD_DATA_DETECTED;   break;       
            case   2:   result = MessageIdEnum.MESSAGE_TIMEOUT;             break;       
            case   3:   result = MessageIdEnum.MESSAGE_NOT_INITIALISED;     break;   
                
            case 100:   result = MessageIdEnum.SYNC_PROCESS_INPUTS;         break;       
            case 101:   result = MessageIdEnum.SYNC_SEND_OUTPUTS;           break;       
            case 102:   result = MessageIdEnum.SYNC_SEND_LAST_TO_CIGI;      break;       
            case 103:   result = MessageIdEnum.SYNC_SEND_LAST_TO_DIS;       break;
                                
            case 200:   result = MessageIdEnum.IOS_HEALTH;                  break;
            case 201:   result = MessageIdEnum.IOS_DESIGNATE_HOST_CONFIG;   break;
            case 202:   result = MessageIdEnum.IOS_PERFORMANCE_RESULT;      break;
                
            case 203:   result = MessageIdEnum.IOS_START_SIMULATING;        break;
            case 204:   result = MessageIdEnum.IOS_STOP_SIMULATING;         break;
            case 205:   result = MessageIdEnum.IOS_REPOSITION;              break;
            case 206:   result = MessageIdEnum.IOS_RECONSTITUTE;            break;
            case 207:   result = MessageIdEnum.IOS_REORIENT;                break;
            case 208:   result = MessageIdEnum.IOS_RESUPPLY;                break;
            case 209:   result = MessageIdEnum.IOS_RESTART_SOFTWARE;        break;
                
            case 300:   result = MessageIdEnum.BEHV_HOST_CONFIG;            break;
                
            case 800:   result = MessageIdEnum.DIS_INCOMING_WRAPPED;        break;
            case 801:   result = MessageIdEnum.DIS_OUTGOING_WRAPPED;        break;                
                
            default:    result = MessageIdEnum.MESSAGE_NONE;                break;       
        }
        
        return result;
    }    
    
    public static short MessageSize( MessageIdEnum msg) {
        short result = 0;
        
        switch( msg ) {
            case MESSAGE_NONE:                  result =  0; break;
            case MESSAGE_BAD_DATA_DETECTED:     result =  0; break;
            case MESSAGE_TIMEOUT:               result =  0; break;
            case MESSAGE_NOT_INITIALISED:       result =  0; break;
                
            case SYNC_PROCESS_INPUTS:           result =  0; break;
            case SYNC_SEND_OUTPUTS:             result =  0; break;
            case SYNC_SEND_LAST_TO_CIGI:        result =  0; break;       
            case SYNC_SEND_LAST_TO_DIS:         result =  0; break;
                
            case IOS_HEALTH:                    result =  4; break;
            case IOS_DESIGNATE_HOST_CONFIG:     result =  4; break;
            case IOS_PERFORMANCE_RESULT:        result = 20; break;
            case IOS_START_SIMULATING:          result =  4; break;
            case IOS_STOP_SIMULATING:           result =  4; break;
            case IOS_REPOSITION:                result =  0; break;
            case IOS_RECONSTITUTE:              result =  0; break;
            case IOS_REORIENT:                  result =  0; break;
            case IOS_RESUPPLY:                  result =  0; break;
            case IOS_RESTART_SOFTWARE:          result =  0; break;
                
            case BEHV_HOST_CONFIG:              result = 68; break;
                
            case DIS_INCOMING_WRAPPED:          result = -1; break; // Variable length
            case DIS_OUTGOING_WRAPPED:          result = -1; break; // Variable length                   

        }
        
        return result;
    }
    
    public static boolean IsIos( MessageIdEnum id) {
        boolean result;        
        switch( id ) {

            case IOS_HEALTH:
            case IOS_DESIGNATE_HOST_CONFIG:
            case IOS_PERFORMANCE_RESULT:
            case IOS_START_SIMULATING:
            case IOS_STOP_SIMULATING:
            case IOS_REPOSITION:
            case IOS_RECONSTITUTE:
            case IOS_REORIENT:
            case IOS_RESUPPLY:
            case IOS_RESTART_SOFTWARE:
                result = true;
                break;
            default:
                result = false;
                break;
        }        
        return result;
    }   
    
    public static boolean IsIos( Message msg) {
        return IsIos(msg.messageID);
    }     
    
    
    public MessageIdEnum messageID = MessageIdEnum.MESSAGE_NONE;
    public byte[]        messageData;
    
    /** Creates a new instance of ServiceMessage */
    public Message() {
        messageData = new byte[MessageSize(messageID)];           
    }    
    
    public Message(MessageIdEnum id) {
        messageID   = id;
        messageData = new byte[MessageSize(messageID)];           
    }       
           
    
    
    public byte[] CreateDatagramFromMessage(Message msg) {
        byte result[];
        
        if((DATAGRAM_HEADER_SIZE + msg.messageData.length) <= MAX_DATAGRAM_SIZE ) {
            result = new byte[DATAGRAM_HEADER_SIZE + msg.messageData.length];
            
            // Text Header to identify a GBTT packet
            result[ 0] = 'G';
            result[ 1] = 'B';
            result[ 2] = 'T';
            result[ 3] = 'T'; 
            
            // The size of the data in bytes
            byte[] dataLenInBytes = Simulation.Utils.ByteArrayUtils.ToByte((short) msg.messageData.length);
            result[ 4] = dataLenInBytes[0];
            result[ 5] = dataLenInBytes[1];
            
            // Reserved bytes
            result[ 6] = 0;
            result[ 7] = 0;                
            result[ 8] = 0;
            result[ 9] = 0;                            
            result[10] = 0;
            result[11] = 0;  
            
            // Message id
            byte[] msgIdInBytes = ByteArrayUtils.ToByte(Message.EnumToInt(msg.messageID));
            result[12] = msgIdInBytes[0];
            result[13] = msgIdInBytes[1];
            result[14] = msgIdInBytes[2];
            result[15] = msgIdInBytes[3];
            
            // Data
            for (int i=0; i<msg.messageData.length; i++) {
                result[16+i] = msg.messageData[i];
            }            
        } else {
            result = new byte[0];
            System.out.println("Message Too Big");   
        }    
        return result;
    }
    
    public static Message CreateMessageFromDataGramBytes( byte[] dg) {
        Message result = new Message(WhatMessageIsThis(dg));

        for (int i=0; i<result.messageData.length; i++) {
            result.messageData[i] = dg[i+DATAGRAM_HEADER_SIZE];
        }          
                
        return result;
    }    
    
    public static MessageIdEnum WhatMessageIsThis( byte[] dg) {
        MessageIdEnum result;
        byte[] sizeBytes;
        byte[] idBytes;        
        short  shortSize;
        int    intID;

        
        // Get The Size
        sizeBytes = ByteArrayUtils.subBytes(dg, 4, 2);
        shortSize = ByteArrayUtils.BytesToShort(sizeBytes);
        
        // Get The ID
        idBytes = ByteArrayUtils.subBytes(dg, 12, 4);
        intID   = ByteArrayUtils.BytesToInt(idBytes); 
        result  = Message.IntToEnum(intID);        
        
        // Check The size against the ID provided it isn't variable
        if(Message.MessageSize(result) >= 0) {
            // fixed size message expected
            if(shortSize != Message.MessageSize(result)) {
                // Something not right.
                result = MessageIdEnum.MESSAGE_BAD_DATA_DETECTED;
            }
        } else {
            // variable sized message. Not currently checking, but could do.
        }
            
        return result;
    }        
    
    
    public static final int DATAGRAM_HEADER_SIZE = 16;
    public static final int MAX_DATAGRAM_SIZE = 1024;    
    
    
}
